/**
 *    title:  tools.c
 *    author:  sleeeeeping
 *    created:  2024-07-11 18:37:47
**/
#include <sys/types.h>
#include <dirent.h>
#include <assert.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>

#include "tools.h"

#define SEC 2.2 * 1000000


void *myMalloc(size_t size, const char *file, const char *func, size_t line) {
	void *ptr = realloc(NULL, size);
	printf("%s %s %lu: malloc %p\n", file, func, line, ptr);
	return ptr;
}

void myFree(void *ptr, const char *file, const char *func, size_t line) {
	printf("%s %s %lu: free %p\n", file, func, line, ptr);
	ptr = realloc(ptr, 0);
}

void cleanStdin() {
	stdin->_IO_read_ptr = stdin->_IO_read_end;
	// scanf("%*[^\n]");
	// scanf("%*c");
}

int readInput() {
	int input = -1;
	while (scanf("%d", &input) == 0) {
		scanf("%*[^\n]");
		scanf("%*c");
	}
	return input;
}

void readStr(char *str, size_t len) {
	size_t rlen = 0; 
	while (rlen == 0) {
		fgets(str, len, stdin);
		rlen = strlen(str);
		if (str[rlen - 1] == '\n') {
			str[rlen - 1] = '\0';
			--rlen;
		} else {
			feedbackView("输入内容过长!");
			rlen = 0;
			scanf("%*[^\n]");
			scanf("%*c");
		}
	}
}

void readName(char *str, size_t len) {
	size_t rlen = 0; 
	while (rlen == 0) {
		fgets(str, len, stdin);
		rlen = strlen(str);
		if (str[rlen - 1] == '\n') {
			str[rlen - 1] = '\0';
			--rlen;
		} else {
			feedbackView("输入内容过长!");
			rlen = 0;
			scanf("%*[^\n]");
			scanf("%*c");
		}
	}
}

#define MIN_PRICE 5.0
#define MAX_PRICE 500.0
float readPrice() {
    float price = 0.0;
    while (scanf("%f", &price) == 0 || price < MIN_PRICE || price > MAX_PRICE) {
        if (price < MIN_PRICE || price > MAX_PRICE) {
			feedbackView("输入价格不符合标准!");
		} else {
			feedbackView("输入价格有误!");
			scanf("%*[^\n]");
			scanf("%*c");
		}
    }
    return price;
}

float readMoney() {
	float money = 0.0;
	while (scanf("%f", &money) == 0 || money * 100 != (int)(money * 100)) {
		if (money * 100 != (int)(money * 100)) {
			feedbackView("输入金额有误（金额应至多为两位小数）请重新输入!");
		} else {
			scanf("%*[^\n]");
			scanf("%*c");
		}
	}
	return money;
}

int readNo() {
	int no = 0;
	while (scanf("%d", &no) == 0) {
		scanf("%*[^\n]");
		scanf("%*c");
	}
	scanf("%*[^\n]");
	scanf("%*c");
	return no;
}

char readConfirm() {
	char ch = 0;
	do {
		while (scanf("%c", &ch) == 0);
		cleanStdin();
		if (!(ch == 'y' || ch == 'n')) {
			printf("请输入[y/n]!\n");
		} else break;
	} while (true);
	return ch;
}

#define PAGE_COUNT 10
char readNPQ() {
	char ch = 0;
	do {
		while (scanf("%c", &ch) == 0);
		cleanStdin();
		if (!(ch == 'n' || ch == 'p' || ch == 'q')) {
			printf("请输入[n/p/q]!\n");
		} else break;
	} while (true);
	return ch;
}

int readId() {
	int id = 0;
	while (scanf("%d", &id) == 0) {
		scanf("%*[^\n]");
		scanf("%*c");
	}
	scanf("%*[^\n]");
	scanf("%*c");
	return id;
}

void readSex(char *sex, size_t len) {
	size_t rlen = 0;
	while (rlen == 0) {
		fgets(sex, len, stdin);
		rlen = strlen(sex);
		if (sex[rlen - 1] == '\n') {
			sex[rlen - 1] = '\0';
			--rlen;
			if (strcmp(sex, "男") == 0 || strcmp(sex, "女") == 0) {
				break;
			} else {
				rlen = 0;
				feedbackView("输入有误，并不是性别(男/女)!");
			}
		} else {
			feedbackView("输入内容过长!");
			rlen = 0;
			scanf("%*[^\n]");
			scanf("%*c");
		}
	}
}

#define MAX_TEL_LEN 11
#define MIN_TEL_LEN 3
void readTel(char *tel, size_t len) {
    size_t rlen = 0; 
	while (rlen == 0) {
		fgets(tel, len, stdin);
		rlen = strlen(tel);
		if (tel[rlen - 1] == '\n') {
			tel[rlen - 1] = '\0';
			--rlen;
            bool isCorrect = true;
            for (int i = 0; tel[i]; ++i) {
                isCorrect &= tel[i] >= '0' && tel[i] <= '9';
            }
            if (rlen < MIN_TEL_LEN || rlen > MAX_TEL_LEN || !isCorrect) {
                feedbackView("输入的电话号码不符合常识!");
                rlen = 0;
            }
		} else {
			feedbackView("输入的电话号码不符合常识!");
			rlen = 0;
			scanf("%*[^\n]");
			scanf("%*c");
		}
	}
}

#define INDENTITYCARD_LEN 18
void readIdentityCard(char *card, size_t len) {
    size_t rlen = 0; 
	while (rlen == 0) {
		fgets(card, len, stdin);
		rlen = strlen(card);
		if (card[rlen - 1] == '\n') {
			card[rlen - 1] = '\0';
			--rlen;
            int tot = 0;
            for (int i = 0; card[i]; ++i) {
                tot += card[i] >= '0' && card[i] <= '9';
            }
            if (!(tot == INDENTITYCARD_LEN || (tot == INDENTITYCARD_LEN - 1 && card[INDENTITYCARD_LEN - 1] == 'X'))) {
                feedbackView("输入的身份证号码不符合常识!");
                rlen = 0;
            }
		} else {
			feedbackView("身份证号码不符合常识!");
			rlen = 0;
			scanf("%*[^\n]");
			scanf("%*c");
		}
	}
}

#define MIN_YEAR 1970
#define MAX_YEAR 2023
int readYear() {
    int year = 0;
    do {
        while (scanf("%d", &year) == 0) {
            scanf("%*[^\n]");
            scanf("%*c");
        }
        if (year < MIN_YEAR || year > MAX_YEAR) {
            feedbackView("输入生日年份不符合常识!");
        } else break;
    } while (true);
    return year;
}


#define MIN_MONTH 1
#define MAX_MONTH 12
int readMonth() {
    int month = 0;
    do {
        while (scanf("%d", &month) == 0) {
            scanf("%*[^\n]");
            scanf("%*c");
        }
        if (month < MIN_MONTH || month > MAX_MONTH) {
            feedbackView("输入生日月份不符合常识!");
        } else break;
    } while (true);
    return month;
}

#define MIN_DAY 1
#define MAX_DAY 31
#define FEB 2
time_t readBirth() {
    struct tm birth = {};
	printf("\n请输入年份:");
    int year = readYear();
	printf("请输入月份:");
    int month = readMonth();
    int day = 0;
	printf("请输入日份:");
    int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    do {
        while (scanf("%d", &day) == 0) {
            scanf("%*[^\n]");
            scanf("%*c");
        }
        if (day < MIN_DAY || day > MAX_DAY || 
            (day > days[month] + ((year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) && month == FEB))) {
            feedbackView("输入生日日份不符合常识");
        } else break;
    } while (true);
    birth.tm_year = year - 1900;
	birth.tm_mon = month - 1;
	birth.tm_mday = day;
    return mktime(&birth);
}


//函数setDispMode用于控制是否开启输入回显功能
//如果option为0，则关闭回显，为1则打开回显

#define DEL 127

int _setDispMode(int fd, int option) {
	int err;
	struct termios term;
	if (tcgetattr(fd, &term) == -1) {
		perror("Cannot get the attribution of the terminal");
		return 1;
	}
	if (option) {
		term.c_lflag |= (ICANON | ECHO);
	} else {
        term.c_lflag &= ~(ICANON | ECHO);
	}
	err = tcsetattr(fd, TCSAFLUSH, &term);
	if (err == -1 && err == EINTR) {
        perror("Cannot set the attribution of the terminal");
        return 1;
	}
	return 0;
}

//函数readpassword用于获得用户输入的密码，并将其存储在指定的字符数组中
int readPassword(char *password, int size, bool isShow) {
	_setDispMode(STDIN_FILENO, !isShow); // 设置输入的内容不会显示出来
	int c;
	int n = 0; 
	do {
		c = getchar();
		if (c == DEL) { // Backspace
			if (n > 0) { // 删除之前输入的一个字符 删除了一个*
				printf("\b");// 退格
				printf(" ");// 覆盖后面的*
				printf("\b");// 退格
				password[--n] = '\0';//把存储的真正的字符删除
				fflush(stdout);
			}
		} else if (c != '\n' && c !='\r') {
			password[n++] = c;
			if (isShow) {
				printf("*"); // 只要不是换行，输入一个字符就用*来替换
				fflush(stdout);
			}
		}
	} while((c != '\n' && c != '\r' && n < (size - 1)) || n == 0);
	password[n] = '\0';
	_setDispMode(STDIN_FILENO, 1); // 恢复回显
	if (isShow) {
		putchar('\n');
	}
	return n;
}

int readAuthority() {
	int authority = 0;
	do {
		while (scanf("%d", &authority) == 0) {
			scanf("%*[^\n]");
			scanf("%*c");
		}
		if (!(authority >= 1 && authority <= 3)) {
			feedbackView("请输入[1/2/3]代表权限!");
		} else break;		
	} while (true);
	return authority;
}

void feedbackView(const char *info) {
    printf("%s\n", info);
	usleep(SEC);
	anyKeyContinue();
}

void anyKeyContinue() {
	cleanStdin();
	printf("请按任意键继续...");
	getchar();
}

bool loadDataFromFile(const char *path, void *ptr, size_t nodeSize) {
	if (path == NULL || ptr == NULL) return false;
	FILE* fp = fopen(path, "r");
	if (fp == NULL) return false;
	int cnt = 0;
	while (fread(ptr + cnt, nodeSize, 1, fp)) {
		cnt += 1;
	}
	fclose(fp);
	return true;
}

void updateDataToFile(const char *path, void *ptr, size_t nodeSize, size_t num) {
    if (path == NULL || ptr == NULL) return ;
    FILE *fp = fopen(path, "w");
    fwrite(ptr, nodeSize, num, fp);
    fclose(fp);
}

bool findFileToPath(const char *path, const char *filename) {
	DIR *dp = opendir(path);
    assert(NULL != dp);
    for (struct dirent *idx = readdir(dp); idx != NULL; idx = readdir(dp)) {
        if (strcmp(idx->d_name, ".") && strcmp(idx->d_name, "..")) {
            if (strcmp(filename, idx->d_name) == 0) {
                closedir(dp);
                return true;
            }
        }
    }
    closedir(dp);
    return false;
}
